/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * Copyright (C) 2016-2020 the AndroidAnnotations project
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.holder;

import com.helger.jcodemodel.AbstractJClass;
import com.helger.jcodemodel.IJAssignmentTarget;
import com.helger.jcodemodel.IJExpression;
import com.helger.jcodemodel.JBlock;
import com.helger.jcodemodel.JExpr;
import com.helger.jcodemodel.JFieldRef;
import com.helger.jcodemodel.JInvocation;
import com.helger.jcodemodel.JMethod;
import com.helger.jcodemodel.JVar;

import org.ohosannotations.helper.CanonicalNameConstants;

import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import static com.helger.jcodemodel.JExpr._this;
import static com.helger.jcodemodel.JExpr.cast;
import static com.helger.jcodemodel.JExpr.invoke;
import static com.helger.jcodemodel.JMod.PUBLIC;

/**
 * 偏好委托
 *
 * @author dev
 * @since 2021-07-22
 */
public class PreferencesDelegate extends GeneratedClassHolderDelegate<EComponentWithViewSupportHolder>
    implements HasPreferences {
    /**
     * 从资源注入块添加首选项
     */
    protected JBlock addPreferencesFromResourceInjectionBlock;
    /**
     * 从资源注入后块添加首选项
     */
    protected JBlock addPreferencesFromResourceAfterInjectionBlock;

    private boolean usingSupportV7Preference = false;
    private boolean usingOhosxPreference = false;
    private AbstractJClass basePreferenceClass;


    /**
     * 偏好委托
     *
     * @param holder 持有人
     */
    public PreferencesDelegate(EComponentWithViewSupportHolder holder) {
        super(holder);
        Elements elementUtils = holder.getEnvironment().getProcessingEnvironment().getElementUtils();
        Types typeUtils = holder.getEnvironment().getProcessingEnvironment().getTypeUtils();

        TypeElement supportV7PreferenceFragmentCompat
            = elementUtils.getTypeElement(CanonicalNameConstants.SUPPORT_V7_PREFERENCE_FRACTIONCOMPAT);
        TypeElement andoridxPreferenceFragmentCompat
            = elementUtils.getTypeElement(CanonicalNameConstants.OHOSX_PREFERENCE_FRAGMENTCOMPAT);
        TypeElement supportV14PreferenceFragment
            = elementUtils.getTypeElement(CanonicalNameConstants.SUPPORT_V14_PREFERENCE_FRACTION);
        TypeElement andoridxPreferenceFragment
            = elementUtils.getTypeElement(CanonicalNameConstants.OHOSX_PREFERENCE_FRAGMENT);

        TypeMirror annotatedType = holder.getAnnotatedElement().asType();

        if (andoridxPreferenceFragmentCompat
            != null && typeUtils.isSubtype(annotatedType, andoridxPreferenceFragmentCompat.asType())
            || andoridxPreferenceFragment
            != null && typeUtils.isSubtype(annotatedType, andoridxPreferenceFragment.asType())) {
            usingOhosxPreference = true;
            basePreferenceClass = getClasses().OHOSX_PREFERENCE;
        } else if (supportV7PreferenceFragmentCompat
            != null && typeUtils.isSubtype(annotatedType, supportV7PreferenceFragmentCompat.asType())
            || supportV14PreferenceFragment
            != null && typeUtils.isSubtype(annotatedType, supportV14PreferenceFragment.asType())) {
            usingSupportV7Preference = true;
            basePreferenceClass = getClasses().SUPPORT_V7_PREFERENCE;
        } else {
            basePreferenceClass = getClasses().PREFERENCE;
        }
    }

    /**
     * 从资源注入块得到添加首选项
     *
     * @return {@link JBlock}
     */
    @Override
    public JBlock getAddPreferencesFromResourceInjectionBlock() {
        if (addPreferencesFromResourceInjectionBlock == null) {
            setAddPreferencesFromResourceBlock();
        }
        return addPreferencesFromResourceInjectionBlock;
    }

    /**
     * 从资源注入块后得到添加首选项
     *
     * @return {@link JBlock}
     */
    @Override
    public JBlock getAddPreferencesFromResourceAfterInjectionBlock() {
        if (addPreferencesFromResourceAfterInjectionBlock == null) {
            setAddPreferencesFromResourceBlock();
        }
        return addPreferencesFromResourceAfterInjectionBlock;
    }

    /**
     * 从资源块设置添加首选项
     */
    private void setAddPreferencesFromResourceBlock() {
        JMethod method
            = getGeneratedClass().method(PUBLIC, codeModel().VOID, "addPreferencesFromResource");
        method.annotate(Override.class);
        JVar preferencesResIdParam = method.param(int.class, "preferencesResId");
        method.body().invoke(JExpr._super(), "addPreferencesFromResource").arg(preferencesResIdParam);
        addPreferencesFromResourceInjectionBlock = method.body().blockVirtual();
        addPreferencesFromResourceAfterInjectionBlock = method.body().blockVirtual();
    }

    /**
     * 找到偏好的关键
     *
     * @param idRef id裁判
     * @return {@link JInvocation}
     */
    private JInvocation findPreferenceByKey(JFieldRef idRef) {
        JInvocation getString = invoke(_this(), "getString").arg(idRef);
        JInvocation findPreferenceByKey = invoke(_this(), "findPreference");
        return findPreferenceByKey.arg(getString);
    }

    /**
     * 会发现偏好持有人
     *
     * @param idRef id裁判
     * @param preferenceClass 偏好类
     * @return {@link FoundPreferenceHolder}
     */
    @Override
    public FoundPreferenceHolder getFoundPreferenceHolder(JFieldRef idRef,
        AbstractJClass preferenceClass) {
        return getFoundPreferenceHolder(idRef, preferenceClass, null);
    }

    /**
     * 会发现偏好持有人
     *
     * @param idRef id裁判
     * @param preferenceClass 偏好类
     * @param fieldRef 现场裁判
     * @return {@link FoundPreferenceHolder}
     */
    @Override
    public FoundPreferenceHolder getFoundPreferenceHolder(JFieldRef idRef,
        AbstractJClass preferenceClass, IJAssignmentTarget fieldRef) {
        String idRefString = idRef.name();
        FoundPreferenceHolder foundPreferenceHolder = (FoundPreferenceHolder) holder.foundHolders.get(idRefString);
        if (foundPreferenceHolder == null) {
            foundPreferenceHolder = createFoundPreferenceAndIfNotNullBlock(idRef, preferenceClass, fieldRef);
            holder.foundHolders.put(idRefString, foundPreferenceHolder);
        }
        return foundPreferenceHolder;
    }

    /**
     * 使用支持v7的偏好
     *
     * @return boolean
     */
    @Override
    public boolean usingSupportV7Preference() {
        return usingSupportV7Preference;
    }

    /**
     * 使用嗳哟偏好
     *
     * @return boolean
     */
    @Override
    public boolean usingOhosPreference() {
        return usingOhosxPreference;
    }

    /**
     * 得到基本偏好类
     *
     * @return {@link AbstractJClass}
     */
    @Override
    public AbstractJClass getBasePreferenceClass() {
        return basePreferenceClass;
    }

    /**
     * 创建发现偏好,如果不是零块
     *
     * @param idRef id裁判
     * @param preferenceClass 偏好类
     * @param fieldRef 现场裁判
     * @return {@link FoundPreferenceHolder}
     */
    private FoundPreferenceHolder createFoundPreferenceAndIfNotNullBlock
    (JFieldRef idRef, AbstractJClass preferenceClass, IJAssignmentTarget fieldRef) {
        IJExpression findPreferenceExpression = findPreferenceByKey(idRef);
        JBlock block = getAddPreferencesFromResourceInjectionBlock();

        if (preferenceClass == null) {
            preferenceClass = basePreferenceClass;
        } else if (!preferenceClass.equals(basePreferenceClass)) {
            findPreferenceExpression = cast(preferenceClass, findPreferenceExpression);
        } else {
        }

        IJAssignmentTarget foundPref = fieldRef;
        if (foundPref == null) {
            foundPref = block.decl(preferenceClass, "preference_" + idRef.name(), findPreferenceExpression);
        } else {
            block.add(foundPref.assign(findPreferenceExpression));
        }
        return new FoundPreferenceHolder(this, preferenceClass, foundPref, block);
    }

    /**
     * 首选项屏幕初始化块
     *
     * @return {@link JBlock}
     */
    @Override
    public JBlock getPreferenceScreenInitializationBlock() {
        // not used
        throw new UnsupportedOperationException();
    }
}
